home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / arcers / tar316.zip / TAR.C < prev    next >
Text File  |  1994-07-03  |  36KB  |  1,080 lines

  1. /* tar.c - Tape ARchive utility program (main function)
  2.  * Author: T.V.Shaporev
  3.  * Creation date: 14 Dec 1990
  4.  *
  5.  * The program works in a same fashion under UNIX (most clones) and MS-DOS.
  6.  * The main idear was to develop a tool for file transferring via diskette
  7.  * between different operating systems - such as all UNIX clones, MS-DOS,
  8.  * RSX, VAX/VMS - and all others which support tar format on a diskette.
  9.  *
  10.  * First step on this way (made in 1989) lies in adapting common UNIX tar
  11.  * program to MS-DOS.
  12.  *
  13.  * On the second step
  14.  *  - some bugs were fixed (especially in DOS-applied codes) and some
  15.  *    optimization were done;
  16.  *  - nonstandard (under DOS) diskette formats were added (i.e.
  17.  *    DEC Rainbow and 80 tracks & 9 sectors format)
  18.  *  - the possibility for compress encoding were included
  19.  *    (this compressor has the best ratio among all others which
  20.  *    I know, but don't ask me about its speed). Compressed-file
  21.  *    format is compatible with the common versions of tar, so You
  22.  *    can extract the compressed image from the archive by the
  23.  *    common program, but I doubt You could uncompress them at last.
  24.  *
  25.  * On the fird step the program was totally (newly) overwritten to bypass
  26.  * any copyright exclamations. In fact, it must be considered new program
  27.  * but I prefer to continue version enumeration (I hope, nobody cares).
  28.  *
  29.  * I think, this program must be called Tar (with capital first letter)
  30.  * to distinguish it from regular UNIX tar.
  31.  *
  32.  * The program's behaviour is analogous to usual tar, and I hope, its
  33.  * internal help will be enough to understand the differences.
  34.  *
  35.  * The program doesn't perform any text file conversion - it passes
  36.  * strict binary image of each file. If You has a problems with reading
  37.  * DOS text files under UNIX (or UNIX files under DOS) please use my
  38.  * dostext program.
  39.  *
  40.  * The program must be compiled by Turbo C 2.0 compiler (in a compact
  41.  * model) under MS-DOS. Please don't replace dynamic arrays back to
  42.  * static and automatic - MS-DOS compilers dislike them.
  43.  *
  44.  *            tim    tim@ecsc.mipt.su    14 Dec 1990
  45.  */
  46. /* Version 3.01
  47.  * Handling of the 'l' option corrected
  48.  */
  49. /* Version 3.02                                       31 Dec 1990
  50.  *  - great deal of minor corrections
  51.  *  - u<pdate> option expanded to extracting
  52.  *  - j<ournal> option added (comment storying files)
  53.  *  - wildcards * and ? are now processed in archive; this may be
  54.  *    suppressed by s<trict> option
  55.  *  - d<elete> option added to replace previous occurencies of files
  56.  *    in archive on storying, or deleting files from archive when
  57.  *    whithout a<dd> parameter - this is for file archives only!
  58.  */
  59. /* Version 3.03                                       22 Feb 1991
  60.  *  - an error corrected in mismatch() (file extract.c)
  61.  *  - decreased stack requirements for tree processing
  62.  *    (see store() in store.c and putfiles() in tar.c)
  63.  *  - added codes to prevent archive file self-storying
  64.  *    (not quite reliable for MS-DOS)
  65.  *  - bincall() invocations changed by calls to rmdir() and mkdir()
  66.  *    this is done automatically for 386/ix and may be switched by
  67.  *    RMKDIR macro
  68.  */
  69. /* Version 3.04                                       29 Jul 1991
  70.  *  - a direct intialization of static global variables inserted into
  71.  *    lzencode() and lzdecode() - see file lzpack.c
  72.  */
  73. /* Version 3.04b                                      03 Oct 1991
  74.  *  - a minor correction of bincall()
  75.  *  - added default block number = sectors on track (MS-DOS)
  76.  */
  77. /* Version 3.05                                       11 Nov 1991
  78.  *  - block factor for diskette writing is set to 1 for most BIOS
  79.  *    compatibility
  80.  *  - scantape() is slightly optimized
  81.  */
  82. /* Version 3.06                                       17 Dec 1991
  83.  *  - n<onest> option applied to all actions (see inarg() in extract.c)
  84.  *  - command-line-extension-file option (responce file) added
  85.  *    for vak (vak@kiae.su) request (see append() in tar.c)
  86.  *  - p<ermission> option added to save directories permissions (UNIX)
  87.  */
  88. /* Version 3.06b                                      22 Dec 1991
  89.  *   - UNIX to DOS renaming algorithm (dot elimination) slightly
  90.  *     changed (see extract.c)
  91.  *   - most of output redirected to stdout (vs stderr)
  92.  */
  93. /* Version 3.07                                       28 Dec 1992
  94.  *   - all unary apostrofs in string constants preserved by backslashes
  95.  *   - reading file list from stdin allowed (see append() in tar.c)
  96.  *   - input redirected to /dev/tty under UNIX
  97.  *   - support for traditional UNIX compression algorithm
  98.  *   - few changes in converting UNIX names for DOS
  99.  */
  100. /* Version 3.07b                                      20 Jan 1993
  101.  *   - gethead() does not return FALSE while errors,
  102.  *     scantape() looks for tape reading errors
  103.  */
  104. /* Version 3.08                                       22 Feb 1993
  105.  *   - method-dependent comression indicator masks (see percent.c)
  106.  *   - 'z' option applied to catalog printing (see catalog())
  107.  *   - compatibility corrections in directory structure checking
  108.  *   - st.st_size == codesize - means file unpacked! (see extract.c)
  109.  */
  110. /* Version 3.09                                       14 Mar 1993
  111.  *   - a bug fixed wich prevents archiving unpacked files at all
  112.  *     (ha-ha!) - see store.c
  113.  *   - changed header description to support new features
  114.  *     see define.h
  115.  *   - support for P1003 and GNU file types - 't' option only! -
  116.  *     see extract.c
  117.  *   - small changes in #ifdef-s to distinguish SCO UNIXes from
  118.  *     XENIXes - see store.c
  119.  *   - regular file processing extracted into separate source
  120.  *     files (see savefile.c & restore.c)
  121.  *   - support for devices and FIFOs added
  122.  *   - 'l' option added for DOS (copy linked files)
  123.  *   - support for System V extents - see extract.c and restore.c
  124.  *     to read archives only, extents may not be unpacked on the
  125.  *     fly - alas, that's all for now
  126.  *   - an error corrected in roll.c
  127.  */
  128. /* Version 3.10                                       28 Jun 1993
  129.  *   - a bug fixed in old compression code (see lzpack.c)
  130.  *   - added possibility to run through compress (',' comma option)
  131.  *     see tar.c, tape.c and compress.c
  132.  *   - comments will not be printed unless 'j' is given (extract.c)
  133.  *   - separated compress-related codes
  134.  */
  135. /* Version 3.11                                       14 Jul 1993
  136.  *   - support for QIC-02 streamers (first version!)
  137.  *     devices supported: fastape, everex
  138.  */
  139. /* Version 3.12                                       29 Sen 1993
  140.  *   - slack area in archive is filled by nulls to improve compression
  141.  *   - added support for Wangtek (QIC-02) device
  142.  *   - a bug fixed in memory release ('pk_out' variable - see _done())
  143.  *   - program support for QIC-02 drive number and tape format
  144.  *     selection
  145.  *   - experimental (!) support for appending QIC-02 tapes
  146.  *     (see qback() in qicface.c)
  147.  *   - LZW support splitted into compressor and extractor and
  148.  *     the letter included in official release (see unlzw.c etc.)
  149.  *   - get default file name from TAPE environment variable
  150.  *   - 'o' flag for DOS means prevent file overwriting
  151.  */
  152. /* Version 3.12b                                      10 Nov 1993
  153.  *   - an error corrected in QIC device selection (see qicface.c)
  154.  *   - eliminated idle rewindings around QIC tape initialisation
  155.  */
  156. /* Version 3.13                                       26 Dec 1993
  157.  *   - online inflatter (unzip) and corresponding '.' (dot) option
  158.  */
  159. /* Version 3.14                                       19 Feb 1994
  160.  *   - online deflatter (zip); compilation model changed to large
  161.  */
  162. /* Version 3.15 - general bugfix                      03 Apr 1994
  163.  *   - strerror() missed in some UNIXes, so psyserr() function added
  164.  *     into tape.c
  165.  *   - extended local header signature inserted in deflated output and
  166.  *     unzclose() changed to uderstand both formats
  167.  *     (see zipdefs.h, zippipe.c and diszip.c)
  168.  *   - pkflush() output is aligned to pksize boundary if output is not
  169.  *     regular file or DOS floppy to avoid block device alignment error
  170.  *     (see tape.c)
  171.  *   - "total blocks" number is reported accordingly to real archive
  172.  *     size (see tape.c, extract.c, tar.c)
  173.  */
  174. /* Version 3.15b - bugfix                             15 Jun 1994
  175.  *   - uname() (see restore.c) bug fixed;
  176.  *   - bi_reverse() cleaned (__emit__ed code cause BC 3.1 error)
  177.  *     moved to trees.c and renamed;
  178.  *   - getlg() changed to look for NEEDBITS buffer;
  179.  *   - diszip.c cleaned a bit.
  180.  */
  181. /* Version 3.16                                       ?? ??? 1994
  182.  *   - got rid of __emit__() - completely;
  183.  *   - got rid of "#pragma pack()" - see define.h;
  184.  *   - error corrected in ct_free() (see trees.c);
  185.  *   - default (-e) compression changed to deflation,
  186.  *     keep support for old-style decompression;
  187.  *   - exclude file(s) specification ('#' option) - up to 16 patterns
  188.  *     (see fmatch.c, store.c, extract.c);
  189.  *   - autodetection of compressed or (g)zipped archives
  190.  *     (pktest() from extract.c etc.)
  191.  */
  192. #include "sysup.h"
  193. #include "modern.h"
  194. #include "zippipe.h"
  195. #include "lzwbits.h"
  196. #include "lzwhead.h"
  197. #include "compress.h"
  198.  
  199. static char note[] = "\n\
  200.    Tape ARchive utility        v3.16%c        (C) 1990-94 Tim V.Shaporev\n";
  201.  
  202. #ifdef USE_COMPRESS
  203. #    define SIGN_VERSION '+'
  204. #else
  205. #    define SIGN_VERSION '-'
  206. #endif
  207.  
  208. #ifdef UNIX
  209. static char help[] = "\n\
  210.    Usage: tar -<options> [tapefile] [blocksize] [disksize] file ...\n\n\
  211.    Options are:                       s - no wildcards for archive\n\
  212.      c - put files to new archive     i - ignore read errors\n\
  213.      a,r - add files to archive       m - forget files origin date/time\n\
  214.      y - move files to archive        o - forget files owner\n\
  215.      x - extract files from archive   l - type missed links\n\
  216.      t - show archive catalog         p - save directories & permissions\n\
  217.      d - delete files in archive      n - no proceed with dir nesting\n\
  218.      u - update files                 / - omit left \'/\' in file names\n\
  219.      v - verbose                      0...7 - number of tape device\n\
  220.      w - acknowledge operations       j - comment storying files\n\
  221.      e - compress encode files        f - next arg is an archive file\n\
  222.      z - old-fashion compression      b - next arg is a blocking factor\n\
  223.      , - run through compressor       @ - next arg is a responce file\n\
  224.      . - run through (g)zip           # - exclude file(s) specification\n\
  225. ";
  226. #endif
  227.  
  228. #ifdef MSDOS
  229. static char help[] = "\n\
  230.    Usage: tar -<options> [tapefile] [blocksize] [disksize] file ...\n\n\
  231.    Options are:\n\
  232.      c - put files to new archive     s - no wildcards for archive\n\
  233.      a,r - add files to archive       m - forget files date/time\n\
  234.      y - move files to archive        n - no proceed with dir nesting\n\
  235.      x - extract files from archive   l - copy linked files\n\
  236.      t - show archive catalog         o - prevent files overwriting\n\
  237.      d - delete files in archive      \\ - omit left \'\\\' in file names\n\
  238.      u - update files                 : - omit DOS drive name\n\
  239.      v - verbose                      0...3 - number of storage device\n\
  240.      w - acknowledge operations       j - comment storying files\n\
  241.      i - ignore read errors           f - next arg is an archive file\n\
  242.      e - compress encode files        b - next arg is a blocking factor\n\
  243.      z - old-fashion compression      k - next arg is K diskette size\n\
  244.      , - run through compressor       @ - next arg is a responce file\n\
  245.      . - run through (g)zip           # - exclude file(s) specification\n\
  246. \n\
  247.    Most of options may be combined. Wildcards * and ? are o\'k\n\
  248. ";
  249. static char devlist[] = "\n\
  250.    The following \"file names\" will be treated as diskette format/size:\n\
  251. \tfd048ss8  - 160K\tfd048ds8  - 320K\tfd135ds9  - 720K\n\
  252. \tfd048ss9  - 180K\tfd048ds9  - 360K\tfd135ds18 - 1.4M\n\
  253. \tfd096ds9  - 720K\tfd096ds15 - 1.2M\trainbow\n\
  254. \n\
  255.    Streamer \"file name\" syntax (full form) is:\n\
  256. \t<device>:base:=<base address>h,dma:=<DRQ>[,irq:=<IRQ>][,norewind]\n\
  257.    Streamer device clones supported are:\n\
  258. \tarchive,\teverex,\t\twangtek\n\
  259. ";
  260. #endif
  261.  
  262. #include <signal.h>
  263. #include <stdio.h>
  264. #ifdef MSDOS
  265. #    include <string.h>
  266. #    include <stdlib.h>
  267. #    include <dos.h>
  268. #    include <dir.h>
  269. #    include <io.h>
  270. #else
  271.     char *strcpy(), *strcat(), *strncpy();
  272.         char *getenv(), *malloc(), *realloc();
  273.     int  open(), read(), close(), link(), unlink(), isatty();
  274.     int  strlen(), strncmp(), atoi();
  275.         void exit(), free();
  276.     long lseek();
  277. #endif
  278.  
  279. #define __ALLOCEXT__
  280. #include "define.h"
  281.  
  282. #include "lzpack.h"
  283. #include "roll.h"
  284.  
  285. #ifdef UNIX
  286. #    ifdef MAXNAMSIZ
  287. #        define MAXPATH MAXNAMSIZ+1
  288. #    else
  289. #        define MAXPATH 512+1
  290. #    endif
  291. #endif
  292.  
  293. #ifdef UNIX
  294. #    ifndef RMKDIR
  295. int bincall(name, args)
  296. char *name, *args;
  297. {
  298.    extern int fork(), execl(), wait();
  299.    int i; register k;
  300.    char b[24];
  301.  
  302.    if (fork() == 0) {
  303.       (void)execl(strcat(strcpy(b, "/bin/"),     name), name, args, 0);
  304.       (void)execl(strcat(strcpy(b, "/usr/bin/"), name), name, args, 0);
  305.       k = -1;
  306.    } else {
  307.       (void)wait(&i); k = i>>8;
  308.    }
  309.    return k;
  310. }
  311. #    endif
  312. #endif
  313.  
  314. #ifdef MSDOS
  315. void takename(dst, src)
  316. register char *dst, *src;
  317. {
  318.    do {
  319.       *(dst++) = *src >= 'A' && *src <= 'Z' ? *src + ('z'-'Z') :
  320.                  *src == '\\' ? '/' : *src;
  321.    } while (*(src++));
  322. }
  323. #endif
  324.  
  325. short headsum(h)
  326. header *h;
  327. {
  328.    register short i, j;
  329.  
  330.    for (i=0, j=0; i<BLKSIZE; i++) {
  331.       j += i >= MAXTNAME+3*8+2*12 && i < MAXTNAME+3*8+2*12+8 ?
  332.            ' ' : *((unsigned char *)h + i);
  333.    }
  334. #if ~0 != 0177777
  335.    return j & 0177777;
  336. #else
  337.    return j;
  338. #endif
  339. }
  340.  
  341. struct node *finditem(name, prev, head)
  342. char *name; struct node **prev, *head;
  343. {
  344.    register struct node *this;
  345.    register i;
  346.  
  347.    *prev = this = head; i = 1;
  348.    while (this && i>0) {
  349.       if ((i = strncmp(name, this->name, MAXTNAME)) > 0) {
  350.          *prev = this; this = this->next;
  351.       }
  352.    }
  353.    return i ? NONE : this;
  354. }
  355.  
  356. struct node *additem(name, prev, head)
  357. char *name; struct node *prev, **head;
  358. {
  359.    register struct node *this;
  360.  
  361.    if ((this = (struct node *)malloc(sizeof(struct node))) == NULL)
  362.       return NONE;
  363.    (void)strncpy(this->name, name, MAXTNAME);
  364.    this->prev = prev;
  365.    if (prev != NONE) {
  366.       if ((this->next = prev->next) != NONE) this->next->prev = this;
  367.       prev->next = this;
  368.    } else {/* initialise the list */
  369.       this->next = NONE;
  370.       (*head) = this;
  371.    }
  372.    return this;
  373. }
  374.  
  375. void delitem(this, head)
  376. struct node *this, **head;
  377. {
  378.    if (this == *head) {/* head of the list */
  379.       if (this->next != NONE) {
  380.          this->next->prev = this->prev != this ? this->prev : this->next;
  381.       }
  382.       this = this->next;
  383.       free(*head);
  384.       *head = this;
  385.    } else {
  386.       if (this->next != NONE) this->next->prev = this->prev;
  387.       this->prev->next = this->next;
  388.       free(this);
  389.    }
  390. }
  391.  
  392. static char *responce = NULL, **argvector = NULL;
  393.  
  394. static void _done __ARGS__(( void ))
  395. {
  396.    register struct node *p, *q;
  397. #ifdef MSDOS
  398.    if (devtype == DEV_QIC2) qend();
  399.    if (archname) free(archname);
  400. #endif
  401.    if (responce) {
  402.       free(responce); free((char*)argvector);
  403.    }
  404.    p = timehead; while (p) { q = p->next; free(p); p = q; }
  405. #ifdef UNIX
  406.    p = linkhead; while (p) { q = p->next; free(p); p = q; }
  407. #endif
  408.    if (hwrite >= 0 && hwrite != handle) {
  409.       (void)close(hwrite); (void)unlink(scratch);
  410.    }
  411.    if (io_2nd && io_2nd!=io_buf) free(io_2nd);
  412.    if (io_buf) free(io_buf);
  413.    if (pk_out && pk_out!=pk_inp) free(pk_out);
  414.    if (pk_inp) free(pk_inp);
  415.    zipfree();
  416.    unzfree();
  417. #ifdef USE_COMPRESS
  418.    z_reltab();
  419. #endif
  420.    z_relmem();
  421.    delroll();
  422. }
  423.  
  424. void done(n)
  425. int n;
  426. {
  427.    _done(); exit(n);
  428. }
  429.  
  430. void outmem(f)
  431. FILE *f;
  432. {
  433.    (void)fprintf(f, "Tar: not enough memory\n");
  434.    done(ESMALL);
  435. }
  436.  
  437. char *salloc(n)
  438. int n;
  439. {
  440.    register char *p;
  441.  
  442.    if ((p = malloc(n)) == NULL) outmem(stderr);
  443.    return p;
  444. }
  445.  
  446. int yes_no(d)
  447. char d;
  448. {
  449.    register int c;
  450. #ifdef MSDOS
  451.    extern int getkey __ARGS__((void));
  452.  
  453.    do {
  454.       c = getkey();
  455.    } while (c!='y' && c!='Y' && c!='n' && c!='N' && c!='q' && c!='Q' &&
  456.             c!='\r' && c!='\n' && c!=27 && c!=3);
  457.    if (c == 3) {
  458.       cbreak = TRUE;
  459.    } else if (c >= ' ') {
  460.       (void)fprintf(stderr, "%c", c);
  461.    } else if (d) {
  462.       (void)fprintf(stderr, "%c", d);
  463.    }
  464.    (void)fprintf(stderr, "\n");
  465. #else
  466.    if ((c = getc(myinp)) == '\n') {
  467.       c = d;
  468.    } else {
  469.       while (getc(myinp) != '\n') ;
  470.    }
  471. #endif
  472.    if (c == 'q' || c == 'Q') done(EXIT);
  473.    return c == 'y' || c == 'Y';
  474. }
  475.  
  476. void prmode(c, m)
  477. char c; int m;
  478. {
  479.    (void)fprintf(myout, "%c%c%c%c%c%c%c%c%c%c", c,
  480.       (m & S_IREAD ? 'r' : '-'), (m & S_IWRITE? 'w' : '-'),
  481.       (m & S_ISUID ? 's' : m & S_IEXEC ? 'x' : '-'),
  482.       (m & 00040   ? 'r' : '-'), (m & 00020   ? 'w' : '-'),
  483.       (m & S_ISGID ? 's' : m & 00010   ? 'x' : '-'),
  484.       (m & 00004   ? 'r' : '-'), (m & 00002   ? 'w' : '-'),
  485.       (m & S_ISVTX ? 't' : m & 00001   ? 'x' : '-'));
  486. }
  487.  
  488. int okwork(c, p, s, n)
  489. char c, p, *n;
  490. struct stat *s;
  491. {
  492.    register m;
  493.  
  494.    (void)fprintf(stderr, "%c ", c);
  495.    if (v_flag) {
  496.       if (p == ' ' && (m = s->st_mode & S_IFMT) != 0) {
  497.          switch (m) {
  498.             case S_IFREG: break;
  499.             case S_IFDIR: p = 'd'; break;
  500.             case S_IFIFO: p = 'p'; break;
  501.             case S_IFCHR: p = 'c'; break;
  502.             case S_IFBLK: p = 'b'; break;
  503. #ifdef S_IFLNK
  504.             case S_IFLNK: p = 'l'; break;
  505. #endif
  506.             default:      p = '?';
  507.          }
  508.       }
  509.       prmode(p, (int)(s->st_mode));
  510.       (void)fprintf(stderr," %3d/%1d %7ld ",s->st_uid,s->st_gid,s->st_size);
  511.    }
  512.    (void)fprintf(stderr, "%s : ", n);
  513.    return YES_NO();
  514. }
  515.  
  516. void onintr() { (void)signal(SIGINT,  SIG_IGN); cbreak = TRUE; }
  517. #ifdef UNIX
  518. void onquit() { (void)signal(SIGQUIT, SIG_IGN); cbreak = TRUE; }
  519. void onhup()  { (void)signal(SIGHUP,  SIG_IGN); cbreak = TRUE; }
  520. #endif
  521.  
  522. static void set_sig __ARGS__(( void ))
  523. {
  524.    if (signal(SIGINT, SIG_IGN) != SIG_IGN) (void)signal(SIGINT, onintr);
  525. #ifdef UNIX
  526.    if (signal(SIGHUP, SIG_IGN) != SIG_IGN) (void)signal(SIGHUP, onhup );
  527.    if (signal(SIGQUIT,SIG_IGN) != SIG_IGN) (void)signal(SIGQUIT,onquit);
  528. #endif
  529. }
  530.  
  531. static void delfile __ARGS__(( void ))
  532. {
  533.    if (v_flag)
  534.       (void)fprintf(myout, "d %s, %ld bytes, %ld tape blocks\n",
  535.          hblock->m.name, st.st_size, (st.st_size + (BLKSIZE-1))/BLKSIZE);
  536.    if (usize()) skipfile();
  537. }
  538.  
  539. static void putfiles __ARGS__(( int, char ** ));
  540.  
  541. static void putfiles(argc, argv)
  542. int argc; char *argv[];
  543. {
  544.    register i;
  545.    char fnmbuf[MAXPATH];
  546.  
  547.    for (i=0; i<argc; i++) {
  548.       if (strlen(argv[i]) > MAXTNAME) {
  549.          (void)fprintf(myout, "Tar: \'%s\' name too long\n", argv[i]);
  550.          continue;
  551.       }
  552.       takename(fnmbuf, argv[i]);
  553.       store(fnmbuf);
  554.    }
  555. }
  556.  
  557. static void append __ARGS__(( int*, char***, char* ));
  558. #define INDMAX 32760
  559. #define INDMIN 1024
  560. #define INDLOW 1023
  561.  
  562. static void append(argc, argv, fname)
  563. int *argc; char ***argv, *fname;
  564. {
  565.    register i;
  566.    register l = 0;
  567.    register n;
  568.  
  569.    if (fname[0] == '-' && fname[1] == '\0') {
  570.       /* standard input */ i = 0;
  571.    } else if ((i = open(fname, O_RDONLY)) < 0 || fstat(i, &st) < 0) {
  572.       (void)fprintf(stderr, "Tar: can\'t process \'%s\'\n", fname);
  573.       done(ERRARG);
  574.    }
  575.    if ((st.st_mode & S_IFMT) == S_IFREG) {
  576.       if (st.st_size >= INDMAX) {
  577.          (void)fprintf(stderr, "Tar: \'%s\' exceeds limit in size\n", fname);
  578.          done(ERRARG);
  579.       }
  580.       responce = salloc((l = (int)st.st_size) + 1);
  581. /* Note: effective text file size differs from the real one under MS-DOS */
  582.       if ((l = read(i, responce, l)) < 1) {
  583.          (void)fprintf(stderr, "Tar: can\'t read \'%s\'\n", fname);
  584.          done(ERRARG);
  585.       }
  586.       (void)close(i);
  587.    } else if ((st.st_mode & S_IFMT) == S_IFCHR || /* character device */
  588.               (st.st_mode & S_IFMT) == S_IFIFO) { /* pipe */
  589.       int j, m; long s;
  590.  
  591.       for (responce=0, m=INDMAX+1; m>=INDMIN; ) {
  592.          if ((responce = malloc(m)) != NULL) goto ok;
  593.          m = ((m+INDLOW) & ~INDLOW) / 2;
  594.       }
  595.       outmem(stderr);
  596. ok:
  597.       s = 0;
  598.       do {
  599.          l = (int)s;
  600.          j = read(i, responce+l, m-l);
  601.          s += j;
  602.       } while (j>0 && s<m);
  603.       if (j < 0) {
  604.          (void)fprintf(stderr, "Tar: error reading \'%s\'\n", fname);
  605.          done(ERRARG);
  606.       }
  607.       if (s >= m) {
  608.          if (m < INDMAX) {
  609.             outmem(stderr);
  610.          } else {
  611.             (void)fprintf(stderr,"Tar: \'%s\' exceeds limit in size\n",fname);
  612.             done(ERRARG);
  613.          }
  614.       }
  615. #ifndef NO_REALLOC
  616.       if (l+1 < m) {
  617.          if ((responce = realloc(responce, l+1)) == NULL) {
  618.             (void)fprintf(stderr, "Tar: error shrinking memory block\n");
  619.             done(ERRARG);
  620.          }
  621.       }
  622. #endif
  623.    } else {
  624.       (void)fprintf(stderr, "Tar: \'%s\' not a file\n", fname);
  625.       done(ERRARG);
  626.    }
  627.    responce[l] = '\0';
  628.  
  629.    i = 0; n = 0;
  630.    while (i<l) { /* count number of words in responce file */
  631.       while (i<l && (responce[i] == ' '  || responce[i] == '\n' ||
  632.                      responce[i] == '\r' || responce[i] == '\t')) ++i;
  633.       if (i<l) ++n; /* next word found */
  634.       while (i<l && responce[i] != ' '  && responce[i] != '\n' &&
  635.                     responce[i] != '\r' && responce[i] != '\t') ++i;
  636.    }
  637.    /* create new argument vector */
  638.    argvector = (char **)salloc((int)((*argc + n) * sizeof(char *)));
  639.    /* copy origin arguments */
  640.    for (i=0; i<*argc; i++) argvector[i] = (*argv)[i];
  641.    *argv = argvector; /* i = *argc; */ *argc += n;
  642.  
  643.    /* append new arguments */
  644.    n = 0;
  645.    while (n < l) {
  646.       while (n<l && (responce[n] == ' '  || responce[n] == '\n' ||
  647.                      responce[n] == '\r' || responce[n] == '\t'))
  648.          responce[n++] = '\0';
  649.       if (n<l) argvector[i++] = responce+n; /* next word found */
  650.       while (n<l && responce[n] != ' '  && responce[n] != '\n' &&
  651.                     responce[n] != '\r' && responce[n] != '\t') ++n;
  652.    }
  653. }
  654.  
  655. static void stdhelp __ARGS__((void))
  656. {
  657.    (void)fprintf(stdout, note, SIGN_VERSION);
  658.    (void)fprintf(stdout, help);
  659.    (void)fflush (stdout);
  660. #ifdef MSDOS
  661.    if (ioctl(fileno(stdout),0) & 0x80) {/* not a disk file */
  662.       (void)fprintf(stderr,"\nDo you want to see device list? ");
  663.       (void)fflush (stderr);
  664.       if (!YES_NO()) return;
  665.    }
  666.    (void)fprintf(stdout, devlist);
  667. #endif
  668. }
  669.  
  670. int pkalloc()
  671. {
  672.    register k;
  673.  
  674.    if (pktype == PKpLZW || pktype == PKZIP) {/* Pipe compression */
  675.       pksize = BLKSIZE;
  676.       k = (d_flag || x_flag || t_flag) && (pk_inp=malloc(pksize))==NULL ||
  677.           (d_flag || a_flag)           && (pk_out=malloc(pksize))==NULL;
  678.    } else {/* Individual file(s) compression */
  679.       pksize = PKSIZE;
  680.       k = (d_flag || x_flag || (t_flag && pktype == PKfLZW)) &&
  681.                                 (pk_out=malloc(pksize))==NULL ||
  682.           (d_flag || a_flag) && (pk_inp=malloc(pksize))==NULL;
  683.    }
  684.    return k;
  685. }
  686.  
  687. int main(argc, argv)
  688. int argc; char *argv[];
  689. {
  690.    register i;
  691.    register char *p;
  692.    char *tapename;
  693.    register k;
  694.    static char m_tape[] = "Tar: tape device multiply defined\n";
  695.    static char bad_lz[] = "Tar: compression method multiply defined\n";
  696.  
  697.    if (argc < 2) {
  698.       stdhelp(); return ERRARG;
  699.    }
  700. #ifdef UNIX
  701.    p_flag = FALSE;
  702. #endif
  703. #ifdef MSDOS
  704.    deldrv   = FALSE;
  705.    setdrive = FALSE;
  706.    filemask = FA_SYSTEM+FA_HIDDEN+FA_RDONLY+FA_DIREC+FA_ARCH;
  707. #endif
  708.    a_flag = x_flag = t_flag = v_flag = u_flag = y_flag = w_flag = i_flag =
  709.    o_flag = m_flag = d_flag = j_flag = s_flag = nonest = dslash = l_flag =
  710.       FALSE;
  711.    pktype = PKNONE;
  712.    pklock = FALSE;
  713.    cblock = 0;
  714.    tapename = NULL;
  715.    myout = stdout;
  716.    xcnt = 0;
  717.  
  718.    p = argv[1]; i = 2;
  719. #ifdef MSDOS
  720.    if (*p == '-' || *p == '/') ++p;
  721. #else
  722.    if (*p == '-') ++p;
  723. #endif
  724.    while (*p) {
  725.       switch(*p>='A' && *p<='Z' ? *p + ('Z'-'z') : *p) {
  726. #ifdef MSDOS
  727.          case 'h':
  728.          case '?': stdhelp();
  729.                    return ERRARG;
  730. #endif
  731.          case 'a':
  732.          case 'r': a_flag = TRUE; break;
  733.          case 'c': c_flag = a_flag = TRUE; break;
  734.          case 'u': u_flag = TRUE; break;
  735.          case 'y': y_flag = a_flag = TRUE; break;
  736.          case 'x': x_flag = TRUE; break;
  737.          case 't': t_flag = TRUE; break;
  738.          case 'v': v_flag = TRUE; break;
  739.          case 'w': w_flag = TRUE; break;
  740.          case 'i': i_flag = TRUE; break;
  741.          case 'm': m_flag = TRUE; break;
  742.          case 'o': o_flag = TRUE; break;
  743.          case 'b': if (cblock) {
  744.                       (void)fprintf(stderr,
  745.                          "Tar: blocksize multiply defined\n");
  746.                       return ERRARG;
  747.                    }
  748.                    if ((cblock = atoi(argv[i++])) < 1 ||
  749.                         cblock > MAXBLOCK) {
  750.                       (void)fprintf(stderr,
  751.                          "Tar: bad blocksize (max is %d)\n", MAXBLOCK);
  752.                       return ERRARG;
  753.                    }
  754.                    break;
  755.          case 'f':
  756.                    if (
  757. #ifdef MSDOS
  758.                        k_flag ||
  759. #endif
  760.                                  tapename) {
  761.                       (void)fprintf(stderr, m_tape); return ERRARG;
  762.                    }
  763.                    tapename = argv[i++];
  764.                    break;
  765.          case 'n': nonest = TRUE;
  766. #ifdef MSDOS
  767.                    filemask = FA_SYSTEM+FA_HIDDEN+FA_RDONLY+FA_ARCH;
  768. #endif
  769.                    break;
  770.          case 'e': k = PKDEF; goto getlevel;
  771.          case '.': k = PKZIP;
  772.          getlevel: if (pktype != PKNONE) {
  773.                       (void)fprintf(stderr, bad_lz); return ERRARG;
  774.                    }
  775.                    pktype = k; pklevel = 6; /* default */
  776.                    if (*(p+1) >= '1' && *(p+1) <= '9') {
  777.                       pklevel = *(p += 1) - '0';
  778.                    }
  779.                    break;
  780.          case ',': k = PKpLZW; goto getbits;
  781.          case 'z': k = PKfLZW;
  782.          getbits : if (pktype != PKNONE) {
  783.                       (void)fprintf(stderr, bad_lz); return ERRARG;
  784.                    }
  785.                    pktype = k; pklevel = BITS;
  786.                    if        (*(p+1) == '9') {
  787.                       p += 1; pklevel = 9;
  788.                    } else if (*(p+1) == '1') {
  789.                       p += 2; pklevel = 10 + *p - '0';
  790.                       if (pklevel < 10 || pklevel > BITS) {
  791.                          (void)fprintf(stderr, "Tar: Invalid bits factor\n");
  792.                          return ERRARG;
  793.                       }
  794.                    }
  795.                    break;
  796.          case 'l': l_flag = TRUE; break;
  797. #ifdef UNIX
  798.          case 'p': p_flag = TRUE; break;
  799. #endif
  800. #ifdef MSDOS
  801.          case 'k': if (k_flag || tapename) {
  802.                       (void)fprintf(stderr, m_tape); return ERRARG;
  803.                    }
  804.                    k_flag = 1;
  805.                    if (argdisk(atoi(argv[i++])) != 0) {
  806.                       (void)fprintf(stderr, "Tar: Invalid diskette size\n");
  807.                       return ERRARG;
  808.                    }
  809.                    break;
  810.  
  811. #endif
  812. #ifdef MSDOS
  813.          case '\\':
  814. #endif
  815. #ifdef UNIX
  816.          case '/':
  817. #endif
  818.                    dslash = TRUE; break;
  819. #ifdef MSDOS
  820.          case ':': deldrv = TRUE; break;
  821. #endif
  822.          case '0': case '1': case '2': case '3':
  823. #ifdef UNIX
  824.          case '4': case '5': case '6': case '7':
  825. #endif
  826.                    if (ndrive) {
  827.                       (void)fprintf(stderr, m_tape); return ERRARG;
  828.                    }
  829. #ifdef MSDOS
  830.                    setdrive = TRUE;
  831. #endif
  832.                    ndrive = *p & 7;
  833.                    break;
  834.          case 'd': d_flag = TRUE; break;
  835.          case 'j': j_flag = TRUE; break;
  836.          case 's': s_flag = TRUE; break;
  837.          case '@': append(&argc, &argv, argv[i++]);
  838.                    break;
  839.          case '#': if (xcnt >= XMAX) {
  840.                      (void)fprintf(stderr, "Tar: too many \'#\'\n");
  841.                      return ERRARG;
  842.                    }
  843.                    xarg[xcnt++] = argv[i++];
  844.                    break;
  845.          default : (void)fprintf(stderr, "Tar: bad option '%c'\n", *p);
  846.                    return ERRARG;
  847.       }
  848.       ++p;
  849.    }
  850.    if (
  851. #ifdef MSDOS
  852.        !k_flag &&
  853. #endif
  854.                   !tapename) tapename = getenv("TAPE");
  855.  
  856.    if (u_flag && !x_flag) a_flag = TRUE;
  857.  
  858.    if (!a_flag && !x_flag && !t_flag && !d_flag) {
  859.       (void)fprintf(stderr, "Tar: nothing to do\n"); return ERRARG;
  860.    }
  861.    if (a_flag || d_flag) {
  862.       if (i >= argc) {
  863.          (void)fprintf(stderr, "Tar: no files specified\n");
  864.          return ERRARG;
  865.       }
  866. #ifndef USE_COMPRESS
  867.       if (pktype == PKfLZW || pktype == PKpLZW) {
  868.          (void)fprintf(stderr,
  869.          "Tar: this restricted version does not support LZW compression\n");
  870.          return ERRARG;
  871.       }
  872. #endif
  873.    }
  874.    if ((a_flag && (x_flag || t_flag)) ||  (x_flag && t_flag) ||
  875.       (!a_flag && (j_flag || dslash)) || (!x_flag && m_flag) ||
  876.        (d_flag && (c_flag || x_flag || t_flag)) ||
  877.        (i_flag && (d_flag || a_flag))) {
  878.       (void)fprintf(stderr, "Tar: incompatible options\n");
  879.       return ERRARG;
  880.    }
  881.    if (m_flag && u_flag) {
  882.       (void)fprintf(stderr, "Tar: 'm' and 'u' options ambiguous\n");
  883.    }
  884.    if ((k = initape(tapename)) != CORRECT) done(k);
  885.    if ((io_buf=getbuf(cblock ? cblock*BLKSIZE : MAXBLOCK*BLKSIZE)) == NULL)
  886.       done(ESMALL);
  887.    io_2nd = io_buf;
  888.    if (pktype != PKNONE) {
  889.       if (pkalloc()) {/* Memory lack */
  890.          if (!w_flag) {
  891.             outmem(stderr);
  892.          } else {
  893.             (void)fprintf(stderr,
  894.                "No memory for [de]compression. Continue? ");
  895.             k = YES_NO();
  896.             (void)fprintf(stderr, "\n");
  897.             if (!k) done(ESMALL);
  898.             if (pk_inp) { free(pk_inp); pk_inp = NULL; }
  899.             pktype = PKNONE;
  900.          }
  901.       }
  902.    }
  903.    cbreak = FALSE;
  904.  
  905.    if ((k = runtape()) != CORRECT) done(k);
  906. #ifdef UNIX
  907.    myinp = stdin;
  908.    if (!isatty(/* stdin */ 0) && (myinp = fopen("/dev/tty", "r")) == NULL) {
  909.       (void)fprintf(myout,
  910.          "Tar: warning: can\'t open terminal device, may be problems\n");
  911.       myinp = stdin;
  912.    }
  913. #endif
  914.  
  915. #ifdef MSDOS
  916.    if (a_flag && isfile) {
  917.       p = tapename;
  918.       if ((p[0]>='A' && p[0]<='Z' || p[0]>='a' && p[0]<='z') && p[1]==':') {
  919.          k = p[0] < 'a' ? p[0] - ('A'-1) : p[0] - ('a'-1); p += 2;
  920.       } else {
  921.          k = 0;
  922.       }
  923.       if (p[0] == '/' || p[0] == '\\') {
  924.          takename((archname = salloc(strlen(p) + 1)), p);
  925.       } else {
  926.          archname = salloc(strlen(p) + MAXPATH);
  927.          *(int *)archname = '/';
  928.          getcurdir(k, archname+1); takename(archname, archname);
  929.          k = strlen(archname);
  930.          archname[k++] = '/';
  931.          takename(archname+k, p);
  932.       }
  933.    }
  934. #endif
  935.    argc -= i; argv += i;
  936.  
  937.    if (d_flag) {
  938.       register header *h; register long l; register m;
  939.  
  940.       if (d_flag && !isfile) {
  941.          (void)fprintf(stderr,
  942.                        "Tar: delete option is for file archives only\n");
  943.          return ERRARG;
  944.       }
  945.       duptape(tapename);
  946.  
  947.       m = FALSE;
  948.       do {
  949.          if ((k = gethead()) == ERROR) done(ERREAD);
  950.          if (!k) continue;
  951.  
  952.          if        (a_flag) {
  953.             struct stat s;
  954.  
  955.              if (inargs(argc, argv, hblock->m.name)) {
  956.                 if (u_flag) uplist();
  957.                 if (stat(hblock->m.name, &s)!=0) {
  958.                    if (v_flag) {
  959.                       (void)fprintf(myout, "Tar: can\'t access \'%s\'\n",
  960.                                             hblock->m.name);
  961.                    }
  962.                 } else if (!u_flag || s.st_mtime > st.st_mtime) {
  963.                    delfile(); continue;
  964.                 }
  965.              }
  966.          } else {/* pure delete */
  967.             if (inargs(argc, argv, hblock->m.name) ||
  968.                ((hblock->m.filetype==TF_LNK || hblock->m.filetype==TF_SYM) &&
  969.                 inargs(argc, argv, hblock->m.linkname))) {
  970.                m = TRUE; delfile(); continue;
  971.             }
  972.          }
  973.  
  974.          /* move file to output archive */
  975.          for (h=steptape(), i=0; i<BLKSIZE/sizeof(int); i++) {
  976.             ((int *)h)[i] = ((int *)hblock)[i];
  977.          }
  978.          if (usize()) {
  979.             l = (st.st_size + (BLKSIZE-1)) / BLKSIZE;
  980.             while (l-- > 0) {
  981.                if ((hblock = readtape()) == NULL) done(ERREAD);
  982.                for (h=steptape(), i=0; i<BLKSIZE/sizeof(int); i++) {
  983.                   ((int *)h)[i] = ((int *)hblock)[i];
  984.                }
  985.             }
  986.          }
  987.       } while (k);
  988.  
  989.       if (a_flag) {
  990.          l = lseek(hwrite, 0L, 1);
  991.          putfiles(argc, argv);
  992.          m = lseek(hwrite, 0L, 1) > l;
  993.       }
  994.  
  995.       if (m) {/* archive was modified */
  996.          endtape();
  997.          if (unlink(tapename)) {
  998.             (void)fprintf(myout, "Tar: can\'t delete \'%s\'\n", tapename);
  999.             done(EWRITE);
  1000.          }
  1001. #ifdef UNIX
  1002.          if (link(scratch, tapename)) {
  1003.             (void)fprintf(myout,
  1004.                "Tar: can\'t link \'%s\' - data stay in \'%s\'\n",
  1005.                tapename, scratch);
  1006.             done(EWRITE);
  1007.          }
  1008.          if (unlink(scratch)) {
  1009.             (void)fprintf(myout, "Tar: can\'t delete scratch file\n");
  1010.          }
  1011. #endif
  1012.  
  1013. #ifdef MSDOS
  1014.          if (rename(scratch, tapename)) {
  1015.             (void)fprintf(myout, "Tar: can\'t rename \'%s\' to \'%s\'\n",
  1016.                                   scratch, tapename);
  1017.             done(EWRITE);
  1018.          }
  1019. #endif
  1020.  
  1021. #ifdef UNIX
  1022.          if (a_flag && l_flag) {
  1023.             register struct node *this;
  1024.  
  1025.             for (this=linkhead; this; this=this->next) {
  1026.                (void)fprintf(myout, "Tar: missed %d link(s) to \'%s\'\n",
  1027.                              this->info.data.count, this->name);
  1028.             }
  1029.          }
  1030. #endif
  1031.       } else {
  1032.          if (v_flag) (void)fprintf(myout, "Tar: archive unchanged\n");
  1033.          (void)close(hwrite);
  1034.          if (unlink(scratch)) {
  1035.             (void)fprintf(myout, "Tar: can\'t delete scratch file\n");
  1036.             done(EWRITE);
  1037.          }
  1038.       }
  1039.    } else if (a_flag) {
  1040. #ifdef MSDOS
  1041.       if (w_flag && c_flag && devtype == DEV_FLOP) {
  1042.          fprintf(stderr,
  1043.                  "\007Data on drive %c: would be destroyed. Continue ? ",
  1044.                  ndrive + 'A');
  1045.          if (!YES_NO()) done(ERRARG);
  1046.       }
  1047. #endif
  1048.       if (a_flag && !c_flag) {
  1049.          scantape(argc, argv, acctime); backtape();
  1050.       }
  1051.       set_sig();
  1052.       putfiles(argc, argv);
  1053.       endtape();
  1054. #ifdef UNIX
  1055.       if (l_flag) {
  1056.          register struct node *this;
  1057.  
  1058.          for (this=linkhead; this; this=this->next) {
  1059.             (void)fprintf(myout, "Tar: missed %d link(s) to \'%s\'\n",
  1060.                           this->info.data.count, this->name);
  1061.          }
  1062.       }
  1063. #endif
  1064.    } else if (x_flag) {
  1065. #ifdef UNIX
  1066.       (void)umask(0);
  1067. #endif
  1068.       scantape(argc, argv, extract);
  1069.    } else {/* if (t_flag) */
  1070.       allbytes = 0; allfiles = 0;
  1071.       scantape(argc, argv, catalog);
  1072.       if (v_flag) {
  1073.          (void)fprintf(myout,
  1074.             "\tTotal %u file(s) for %lu bytes in %lu tape blocks\n",
  1075.             allfiles, allbytes, allblock);
  1076.       }
  1077.    }
  1078.    _done(); return 0;
  1079. }
  1080.